#include "vm/swap.h"
#include <bitmap.h>
#include "threads/thread.h"
#include "threads/malloc.h"
#include "userprog/pagedir.h"
#include <list.h>
#include "vm/spage.h"

void swap_init(void){
  swap_bitmap = bitmap_create(MAX_SWAP_DISK_SECTOR);
  bitmap_set_all(swap_bitmap,false);
  list_init(&swap_list);
  swap_block = block_get_role(BLOCK_SWAP);
}

void swap_out(void * upage,void * buffer){
  struct swap_entry * sw_entry = malloc(sizeof(struct swap_entry));
  sw_entry->upage = upage;
  sw_entry->start_sector = bitmap_scan_and_flip(swap_bitmap,0,8,false);
  block_write_page(swap_block,sw_entry->start_sector,buffer);
  sw_entry->holder_tid = thread_current()->tid; //save the holder tid for later use
  list_push_back(&swap_list,&sw_entry->swap_elem); //add to swap_list
}

void swap_in(void * upage){
  struct list_elem * e;
  struct swap_entry * sw_entry = NULL;
  struct thread * t = thread_current();
  /* search for matching element in swap_list */
  for(e = list_begin(&swap_list) ; e != list_end(&swap_list);
      e = list_next(e)){
    sw_entry = list_entry(e,struct swap_entry,swap_elem);
    if(sw_entry->upage == upage)
      break;
  }
  void * buffer = get_frame(PAL_USER | PAL_ZERO);
  block_read_page(swap_block,sw_entry->start_sector,buffer);

  pagedir_set_page (t->pagedir, upage, buffer, spage_lookup(upage)->writable);

  bitmap_set_multiple(swap_bitmap,sw_entry->start_sector,8,false);
  list_remove(&sw_entry->swap_elem);
  free(sw_entry);
}

void block_read_page(struct block *block,size_t start_sector,void * buffer){
  int sector;
  for(sector = start_sector; sector < start_sector + 8; sector++){
    block_write(block,sector,buffer+(512*sector));
  }
}


void block_write_page(struct block *block,size_t start_sector,void * buffer){
  int sector;
  for(sector = start_sector; sector < start_sector + 8; sector++){
    block_write(block,sector,buffer+(512*sector));
  }
}





